package com.weizhu.swufer.autoconfiguration;

import com.weizhu.swufer.constant.SwuferConstant;
import com.weizhu.swufer.core.annotation.SwuferFilter;
import com.weizhu.swufer.core.client.DefaultGenericService;
import com.weizhu.swufer.core.client.GenericService;
import com.weizhu.swufer.core.client.ReferenceConfig;
import com.weizhu.swufer.core.client.SwuferReferenceInstantiationAwareBeanPostProcessor;
import com.weizhu.swufer.core.entity.RpcBaseInfo;
import com.weizhu.swufer.core.filter.Filter;
import com.weizhu.swufer.core.filter.FilterManager;
import com.weizhu.swufer.core.server.SwuferBootstrap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;

@Configuration
@EnableConfigurationProperties(SwuferProperties.class)
public class SwuferRpcServiceAutoConfiguration implements ApplicationContextAware, BeanFactoryAware, InstantiationAwareBeanPostProcessor {

    private ApplicationContext applicationContext;

    private BeanFactory beanFactory;
    @Autowired
    SwuferProperties swuferProperties;

    private static final Logger logger = LoggerFactory.getLogger(SwuferRpcServiceAutoConfiguration.class);

    @Bean
    public SwuferReferenceInstantiationAwareBeanPostProcessor referenceInstantiationAwareBeanPostProcessor(){
        getSwuferBootstrap();
        return new SwuferReferenceInstantiationAwareBeanPostProcessor(swuferProperties,applicationContext);
    }


    public SwuferBootstrap getSwuferBootstrap() {
        Properties properties = new Properties();


        properties.setProperty(SwuferConstant.PROPERTIES_PORT,String.valueOf(swuferProperties.getPort()));
        String registryType = swuferProperties.getRegistryType() == null?"zookeeper":swuferProperties.getRegistryType();
        properties.setProperty(SwuferConstant.PROPERTIES_REGISTRY_TYPE,registryType);
        properties.setProperty(SwuferConstant.PROPERTIES_REGISTRY_ADDRESS,swuferProperties.getRegistryAddress());
        properties.setProperty(SwuferConstant.PROPERTIES_WEIGHT,String.valueOf(swuferProperties.getWeight()));
        properties.setProperty(SwuferConstant.PROPERTIES_CLUSTER,swuferProperties.getCluster());
        properties.setProperty(SwuferConstant.PROPERTIES_LOADBALANCER,swuferProperties.getLoadBalancer());
        properties.setProperty(SwuferConstant.PROPERTIES_MAX_WAIT_TIME,String.valueOf(swuferProperties.getMaxWaitTime()));
        properties.setProperty(SwuferConstant.PROPERTIES_LAZY_START,String.valueOf(swuferProperties.getLazyStart()));
        RpcInfoScanner scanner = new RpcInfoScanner(applicationContext,beanFactory);
        scanner.setProperties(properties);
        scanner.readRpcBaseInfo();
        List<RpcBaseInfo> rpcBaseInfoList = scanner.getRpcBaseInfoList();
        SwuferBootstrap bootstrap = SwuferBootstrap.getInstance(properties);
        bootstrap.setRpcBaseInfoList(rpcBaseInfoList);

        registerFilters();
        return bootstrap;
    }

    @Bean
    public GenericService genericService(){
        ReferenceConfig referenceConfig = new ReferenceConfig(swuferProperties);
        return new DefaultGenericService(referenceConfig);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    private void registerFilters() {
        FilterManager filterManager = FilterManager.getInstance();
        RpcInfoScanner scanner = new RpcInfoScanner();
        try {
            scanner.scanFilter("com.weizhu.swufer.core.filter");
        }catch (Exception e){
            e.printStackTrace();
        }
        Map<String, Object> beansWithFilter = applicationContext.getBeansWithAnnotation(SwuferFilter.class);
        for (Object obj : beansWithFilter.values()) {
            filterManager.registerFilter(obj);
        }
        filterManager.sort();
    }
}
